/*
 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define HST_LOG_TAG "Minimp3DemuxerPlugin"

#include "minimp3_demuxer_plugin.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <new>
#include "core/plugin_manager.h"
#include "foundation/log.h"
#include "utils/memory_helper.h"
#include "osal/thread/scoped_lock.h"
#include "plugin/common/plugin_buffer.h"

namespace OHOS {
namespace Media {
namespace Plugin {
namespace {
constexpr uint32_t MAX_SAMPLES_PERFRAME    = 1152 * 2;
constexpr uint32_t MP3_SEEK_DISCARD_ITEMS  = 2;
constexpr uint32_t ID3_DETECT_SIZE         = 10;
constexpr uint32_t PROBE_READ_LENGTH       = 16 * 1024;
constexpr uint32_t MAX_RANK                = 100;
constexpr uint32_t MAX_FRAME_SIZE          = 16 * 1024;
constexpr uint32_t MEDIA_IO_SIZE           = 12 * 1024;
AudioDemuxerMp3Attr mp3ProbeAttr;
AudioDemuxerRst mp3ProbeRst;
std::vector<uint32_t> infoLayer         = {1, 2, 3};
std::vector<uint32_t> infoSampleRate    = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000};
std::vector<uint32_t> infoBitrateKbps   = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 
                                           192, 224, 256, 288, 320, 352, 384, 416, 448};
size_t AudioDecmuxerMp3Id3v2SizeCalculate(const uint8_t *buf);
bool AudioDemuxerMp3HasId3v2(const uint8_t *buf);
size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize);
int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info);
int AudioDemuxerMp3IterateCallbackForProbe(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, 
                                           size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info);
Status AudioDemuxerMp3Probe(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *inputBuffer, uint32_t inputLength, 
                            AudioDemuxerRst *mp3DemuxerRst);
int Sniff(const std::string& name, std::shared_ptr<DataSource> dataSource);
Status RegisterPlugin(const std::shared_ptr<Register>& reg);
void UpdatePluginDefinition(CodecPluginDef& definition);
}

Minimp3DemuxerPlugin::Minimp3DemuxerPlugin(std::string name)
    : DemuxerPlugin(std::move(name)),
      ioContext_(),
      mediaIOSize_(MEDIA_IO_SIZE),
      fileSize_(0)
{
    FALSE_LOG(memset_s(&mp3DemuxerAttr_, sizeof(mp3DemuxerAttr_), 0x00, sizeof(AudioDemuxerMp3Attr)) == 0);
    FALSE_LOG(memset_s(&mp3DemuxerRst_, sizeof(mp3DemuxerRst_), 0x00, sizeof(AudioDemuxerRst)) == 0);
    FALSE_LOG(memset_s(&mp3ProbeAttr, sizeof(mp3ProbeAttr), 0x00, sizeof(AudioDemuxerMp3Attr)) == 0);
    FALSE_LOG(memset_s(&mp3ProbeRst, sizeof(mp3ProbeRst), 0x00, sizeof(AudioDemuxerRst)) == 0);
    MEDIA_LOG_I("Minimp3DemuxerPlugin, plugin name: %s", pluginName_.c_str());
}

Minimp3DemuxerPlugin::~Minimp3DemuxerPlugin()
{
    MEDIA_LOG_I("~Minimp3DemuxerPlugin");
}

Status Minimp3DemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource>& source)
{
    ioContext_.dataSource = source;
    if (ioContext_.dataSource != nullptr) {
        ioContext_.dataSource->GetSize(fileSize_);
    }
    mp3DemuxerAttr_.fileSize = fileSize_;
    MEDIA_LOG_I("fileSize_ %d", fileSize_);
    return Status::OK;
}

Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo)
{
    Status status = Status::ERROR_UNKNOWN;
    auto buffer = std::make_shared<Buffer>();
    auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_);
    int processLoop = 1;
    uint8_t *inputDataPtr = nullptr;
    while (processLoop) {
        auto result = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast<size_t>(mediaIOSize_));
        inputDataPtr = const_cast<uint8_t *>(bufData->GetReadOnlyData());
        status = AudioDemuxerMp3Prepare(&mp3DemuxerAttr_, inputDataPtr, bufData->GetSize(), &mp3DemuxerRst_);
        switch (status) {
            case Status::ERROR_NOT_ENOUGH_DATA:
                ioContext_.offset = mp3DemuxerRst_.usedInputLength;
                processLoop = 1;
                break;
            case Status::OK:
                ioContext_.offset = mp3DemuxerRst_.usedInputLength;

                mediaInfo.tracks.resize(1);
                if (mp3DemuxerRst_.frameChannels == 1) {
                    mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::MONO});
                } else {
                    mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO});
                }
                mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_RATE, (uint32_t)mp3DemuxerRst_.frameSampleRate});
                mediaInfo.tracks[0].insert({Tag::MEDIA_BITRATE, (uint32_t)mp3DemuxerRst_.frameBitrateKbps});
                mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNELS, (uint32_t)mp3DemuxerRst_.frameChannels});
                mediaInfo.tracks[0].insert({Tag::TRACK_ID, (uint32_t)0});
                mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)});
                mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(1)});
                mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, (uint32_t)(mp3DemuxerRst_.audioLayer)});
                mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PER_FRAME, (uint32_t)(mp3DemuxerRst_.samplesPerFrame)});

                processLoop = 0;
                break;
            case Status::ERROR_UNSUPPORTED_FORMAT:
                return Status::ERROR_UNSUPPORTED_FORMAT;
            case Status::ERROR_UNKNOWN:
            default:
                processLoop = 0;
                MEDIA_LOG_I("AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT %d", status);
                return Status::ERROR_UNKNOWN;
        }
    }

    return Status::OK;
}

Status Minimp3DemuxerPlugin::ReadFrame(Buffer& outBuffer, int32_t timeOutMs)
{
    int  status  = -1;
    std::shared_ptr<Memory> mp3FrameData;
    auto buffer  = std::make_shared<Buffer>();
    auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_);
    auto result  = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast<size_t>(mediaIOSize_));
    if (result != Status::OK) {
        ioContext_.eos = true;
        ioContext_.offset = 0;
        MEDIA_LOG_I("result is %d", result);
        return result;
    }

    uint8_t *inputPtr = const_cast<uint8_t *>(bufData->GetReadOnlyData());
    status = AudioDemuxerMp3Process(inputPtr, bufData->GetSize());

    if (outBuffer.IsEmpty()) {
        mp3FrameData = outBuffer.AllocMemory(nullptr, mp3DemuxerRst_.frameLength);
    } else {
        mp3FrameData = outBuffer.GetMemory();
    }
    switch (status) {
        case AUDIO_DEMUXER_SUCCESS:
            ioContext_.offset = mp3DemuxerRst_.usedInputLength;
            mp3FrameData->Write(mp3DemuxerRst_.frameBuffer, mp3DemuxerRst_.frameLength);
            if (mp3DemuxerRst_.frameBuffer) {
                free(mp3DemuxerRst_.frameBuffer);
                mp3DemuxerRst_.frameBuffer = nullptr;
            }
            break;
        case AUDIO_DEMUXER_ERROR:
        default:
            if (mp3DemuxerRst_.frameBuffer) {
                free(mp3DemuxerRst_.frameBuffer);
                mp3DemuxerRst_.frameBuffer = nullptr;
            }
            return Status::ERROR_UNKNOWN;
    }

    return Status::OK;
}

Status Minimp3DemuxerPlugin::SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode)
{
    uint64_t pos = 0;
    uint32_t targetTtimeS = static_cast<uint32_t>(timeStampUs / (1000 * 1000));
    if (AudioDemuxerMp3GetSeekPosition(targetTtimeS, &pos) == 0) {
        mp3DemuxerRst_.usedInputLength = pos;
    } else {
        return Status::ERROR_INVALID_PARAMETER;
    }

    return Status::OK;
}

Status Minimp3DemuxerPlugin::Init()
{
    minimp3DemuxerImpl_ = MiniMp3GetOpt();
    AudioDemuxerMp3Open();

    return Status::OK;
}

Status Minimp3DemuxerPlugin::Deinit()
{
    return Status::OK;
}

Status Minimp3DemuxerPlugin::Prepare()
{
    return Status::OK;
}

Status Minimp3DemuxerPlugin::Reset()
{
    ioContext_.eos = false;
    ioContext_.dataSource.reset();
    ioContext_.offset = 0;
    return Status::OK;
}

Status Minimp3DemuxerPlugin::Start()
{
    return Status::OK;
}

Status Minimp3DemuxerPlugin::Stop()
{
    return Status::OK;
}

bool Minimp3DemuxerPlugin::IsParameterSupported(Tag tag)
{
    return false;
}

Status Minimp3DemuxerPlugin::GetParameter(Tag tag, ValueType &value)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status Minimp3DemuxerPlugin::SetParameter(Tag tag, const ValueType &value)
{
    return Status::ERROR_UNIMPLEMENTED;
}

std::shared_ptr<Allocator> Minimp3DemuxerPlugin::GetAllocator()
{
    return nullptr;
}

Status Minimp3DemuxerPlugin::SetCallback(const std::shared_ptr<Callback>& cb)
{
    return Status::OK;
}

size_t Minimp3DemuxerPlugin::GetTrackCount()
{
    return 0;
}
Status Minimp3DemuxerPlugin::SelectTrack(int32_t trackId)
{
    return Status::OK;
}
Status Minimp3DemuxerPlugin::UnselectTrack(int32_t trackId)
{
    return Status::OK;
}
Status Minimp3DemuxerPlugin::GetSelectedTracks(std::vector<int32_t>& trackIds)
{
    return Status::OK;
}

void Minimp3DemuxerPlugin::AudioDemuxerMp3IgnoreTailZero(uint8_t *data, uint32_t *dataLen)
{
    if ((data == nullptr) || (dataLen == nullptr) || (*dataLen == 0)) {
        return;
    }

    uint32_t len = *dataLen;
    uint8_t  *ptr = data + len - 1;

    do {
        if (*ptr == 0) {
            ptr--;
            len--;
        } else {
            break;
        }
    } while (len);

    *dataLen = len;
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallback(void *userData, const uint8_t *frame, int frameSize, 
                                                         int freeFormatBytes, size_t bufSize, uint64_t offset, 
                                                         Mp3DemuxerFrameInfo *info)
{
    AudioDemuxerMp3Attr *mp3Demuxer = static_cast<AudioDemuxerMp3Attr *>(userData);
    AudioDemuxerRst *rst = mp3Demuxer->rst;
    uint64_t usedInputLength = 0;

    if (mp3Demuxer->internalRemainLen >= frameSize) {
        usedInputLength = offset + frameSize;
    } else {
        usedInputLength = offset;
    }

    if (frameSize == 0) {
        rst->usedInputLength = 0;
        rst->frameBuffer = nullptr;
        rst->frameLength = 0;
        return 0;
    }

    if (frameSize >= MAX_FRAME_SIZE) {
        return AUDIO_DEMUXER_ERROR;
    }

    uint8_t *rstFrame = static_cast<uint8_t *>(calloc(frameSize, sizeof(uint8_t)));
    if (!rstFrame) {
        return AUDIO_DEMUXER_ERROR;
    }

    (void)memcpy_s(rstFrame, frameSize, frame, frameSize);
    rst->frameBuffer = rstFrame;
    rst->frameLength = frameSize;
    rst->frameBitrateKbps = info->bitrate_kbps;
    rst->frameChannels    = info->channels;
    rst->frameSampleRate  = info->hz;
    rst->usedInputLength += usedInputLength;
    return 1;
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, 
                                                                   int frameSize, int freeFormatBytes,
                                                                   size_t bufSize, uint64_t offset, 
                                                                   Mp3DemuxerFrameInfo *info)
{
    return AudioDemuxerMp3IterateCallbackForProbe(userData, frame, frameSize, freeFormatBytes, bufSize, offset, info);
}

void Minimp3DemuxerPlugin::AudioDemuxerMp3Open()
{
    minimp3DemuxerImpl_.init(&mp3DemuxerAttr_.mp3DemuxerHandle);
    return;
}

int  Minimp3DemuxerPlugin::AudioDemuxerMp3Close()
{
    return 0;
}

Status Minimp3DemuxerPlugin::AudioDemuxerMp3Prepare(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *buf, uint32_t len, 
                                                    AudioDemuxerRst *mp3DemuxerRst)
{
    return AudioDemuxerMp3Probe(mp3DemuxerAttr, buf, len, mp3DemuxerRst);
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3Process(uint8_t *buf, uint32_t len)
{
    if ((buf == nullptr) || (len <= 0)) {
        MEDIA_LOG_I("%s arg error", __func__);
        return AUDIO_DEMUXER_ERROR;
    }
    int ret = 0;
    uint32_t processLen = len;
    AudioDemuxerMp3IgnoreTailZero(buf, &processLen);
    mp3DemuxerAttr_.rst = &mp3DemuxerRst_;
    mp3DemuxerAttr_.internalRemainLen = processLen;
    ret = minimp3DemuxerImpl_.iterateBuf(buf, processLen, AudioDemuxerMp3IterateCallback, &mp3DemuxerAttr_);

    if (mp3DemuxerAttr_.mp3SeekFlag == 1 && mp3DemuxerAttr_.discardItemCount < MP3_SEEK_DISCARD_ITEMS) {
        (void)memset_s(mp3DemuxerRst_.frameBuffer, mp3DemuxerRst_.frameLength, 0x00, mp3DemuxerRst_.frameLength);
        mp3DemuxerAttr_.discardItemCount++;
    } else {
        mp3DemuxerAttr_.discardItemCount = 0;
        mp3DemuxerAttr_.mp3SeekFlag = 0;
    }
    if (ret == 0 || ret == 1) {
        return AUDIO_DEMUXER_SUCCESS;
    } else {
        return AUDIO_DEMUXER_ERROR;
    }
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3FreeFrame(uint8_t *frame)
{
    if (frame) {
        free(frame);
        return 0;
    } else {
        return -1;
    }
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3Seek(uint32_t pos, uint8_t *buf, uint32_t len, AudioDemuxerRst *rst)
{
    return 0;
}

int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos)
{
    if (!pos) {
        MEDIA_LOG_I("pos nullptr error");
        return AUDIO_DEMUXER_ERROR;
    }
    uint32_t targetPos = targetTtimeS * mp3DemuxerAttr_.bitRate * 1000 / 8 + mp3DemuxerAttr_.id3v2Size;
    if (targetPos > mp3DemuxerAttr_.fileSize) {
        *pos = 0;
        return -1;
    }
    *pos = static_cast<uint64_t>(targetPos);
    mp3DemuxerAttr_.mp3SeekFlag = 1;
    return 0;
}

namespace {
    size_t AudioDecmuxerMp3Id3v2SizeCalculate(const uint8_t *buf)
    {
        return (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10;
    }

    bool AudioDemuxerMp3HasId3v2(const uint8_t *buf)
    {
        return !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || 
                      (buf[8] & 0x80) || (buf[9] & 0x80));
    }

    size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize)
    {
        if (bufSize >= ID3_DETECT_SIZE && AudioDemuxerMp3HasId3v2(buf)) {
            size_t id3v2Size = AudioDecmuxerMp3Id3v2SizeCalculate(buf);
            if ((buf[5] & 16)) { // 5, 16
                id3v2Size += 10; // 10
            }
            return id3v2Size;
        }
        return 0;
    }

    int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info)
    {
        if (!info) {
            return -1;
        }

        std::vector<uint32_t>::iterator it = find (infoLayer.begin(), infoLayer.end(), info->layer);
        if (it == infoLayer.end()) {
            return -1;
        }

        it = find (infoSampleRate.begin(), infoSampleRate.end(), info->hz);
        if (it == infoSampleRate.end()) {
            return -1;
        }

        it = find (infoBitrateKbps.begin(), infoBitrateKbps.end(), info->bitrate_kbps);
        if (it == infoBitrateKbps.end()) {
            return -1;
        }

        return 0;
    }

    int AudioDemuxerMp3IterateCallbackForProbe(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes,
                                               size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info)
    {
        int sampleCount;
        Minimp3WrapperMp3decFrameInfo frameInfo;
        AudioDemuxerMp3Attr *mp3Demuxer = static_cast<AudioDemuxerMp3Attr *>(userData);
        AudioDemuxerRst *rst  = mp3Demuxer->rst;
        rst->frameBitrateKbps = info->bitrate_kbps;
        rst->frameChannels    = info->channels;
        rst->frameSampleRate  = info->hz;
        rst->audioLayer       = info->layer;
        rst->samplesPerFrame  = info->samples_per_frame;
        sampleCount = Minimp3WrapperMp3decDecodeFrame(&mp3Demuxer->mp3DemuxerHandle, frame, frameSize, 
                                                      mp3Demuxer->probePcmBuf, &frameInfo);
        if (sampleCount <= 0 && AudioDemuxerMp3ProbeDecodeCheck(info) != 0) {
            return -1;
        }

        return 1;
    }

    Status AudioDemuxerMp3Probe(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *inputBuffer, uint32_t inputLength, 
                                AudioDemuxerRst *mp3DemuxerRst)
    {
        if ((inputBuffer == nullptr) || (inputLength <= 0)) {
            MEDIA_LOG_I("%s arg error", __func__);
            return Status::ERROR_INVALID_PARAMETER;
        }
        int ret;

        if (mp3DemuxerAttr->id3v2SkipFlag == 0) {
            if (mp3DemuxerAttr->id3v2Offset == 0) {
                if (inputLength < ID3_DETECT_SIZE) {
                    mp3DemuxerRst->usedInputLength = 0;
                    return Status::ERROR_NOT_ENOUGH_DATA;
                } else {
                    mp3DemuxerAttr->id3v2Size = AudioDemuxerMp3GetId3v2Size(inputBuffer, inputLength);
                    mp3DemuxerAttr->id3v2Offset = mp3DemuxerAttr->id3v2Size;
                }
            }

            if (mp3DemuxerAttr->id3v2Offset) {
                MEDIA_LOG_D("mp3 id3v2Offset = %d, input data inputLength %d", mp3DemuxerAttr->id3v2Offset,
                            inputLength);
                if (inputLength >= mp3DemuxerAttr->id3v2Offset) {
                    mp3DemuxerRst->usedInputLength = mp3DemuxerAttr->id3v2Offset;
                    mp3DemuxerAttr->id3v2SkipFlag  = 1;
                    inputLength -= mp3DemuxerAttr->id3v2Offset;
                    inputBuffer += mp3DemuxerAttr->id3v2Offset;
                    mp3DemuxerAttr->id3v2Offset = 0;
                } else {
                    mp3DemuxerRst->usedInputLength = inputLength;
                    mp3DemuxerAttr->id3v2Offset = mp3DemuxerAttr->id3v2Offset - inputLength;
                    return Status::ERROR_NOT_ENOUGH_DATA;
                }
            }
        }
        mp3DemuxerAttr->rst = mp3DemuxerRst;
        mp3DemuxerAttr->internalRemainLen = inputLength;
        ret = Minimp3WrapperMp3decIterateBuf(inputBuffer, inputLength, AudioDemuxerMp3IterateCallbackForProbe, 
                                             mp3DemuxerAttr);
        if (ret != 1) {
            if (mp3DemuxerAttr->id3v2SkipFlag) {
                return Status::ERROR_NOT_ENOUGH_DATA;
            }
            return Status::ERROR_UNSUPPORTED_FORMAT;
        }
        MEDIA_LOG_I("bitrate_kbps = %d info->channels = %d info->hz = %d", (uint32_t)mp3DemuxerRst->frameBitrateKbps,
                    (uint32_t)mp3DemuxerRst->frameChannels, (uint32_t)mp3DemuxerRst->frameSampleRate);
        return Status::OK;
    }

    int Sniff(const std::string& name, std::shared_ptr<DataSource> dataSource)
    {
        Status status = Status::ERROR_UNKNOWN;
        auto buffer = std::make_shared<Buffer>();
        auto bufData = buffer->AllocMemory(nullptr, PROBE_READ_LENGTH);
        int processLoop = 1;
        uint8_t *inputDataPtr = nullptr;
        int offset = 0;
        while (processLoop) {
            auto result = dataSource->ReadAt(offset, buffer, static_cast<size_t>(PROBE_READ_LENGTH));
            inputDataPtr = const_cast<uint8_t *>(bufData->GetReadOnlyData());
            status = AudioDemuxerMp3Probe(&mp3ProbeAttr, inputDataPtr, bufData->GetSize(), &mp3ProbeRst);
            switch (status) {
                case Status::ERROR_NOT_ENOUGH_DATA:
                    offset = mp3ProbeRst.usedInputLength;
                    processLoop = 1;
                    break;
                case Status::OK:
                    offset = mp3ProbeRst.usedInputLength;
                    processLoop = 0;
                    break;
                case Status::ERROR_UNSUPPORTED_FORMAT:
                    return 0;
                case Status::ERROR_UNKNOWN:
                default:
                    processLoop = 0;
                    MEDIA_LOG_I("AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT %d", status);
                    return 0;
            }
        }
        return MAX_RANK;
    }

    Status RegisterPlugin(const std::shared_ptr<Register>& reg)
    {
        MEDIA_LOG_I("RegisterPlugin called.");
        if (!reg) {
            MEDIA_LOG_I("RegisterPlugin failed due to nullptr pointer for reg.");
            return Status::ERROR_INVALID_PARAMETER;
        }

        std::string pluginName = "Minimp3DemuxerPlugin";
        DemuxerPluginDef regInfo;
        regInfo.name = pluginName;
        regInfo.description = "adapter for minimp3 demuxer plugin";
        regInfo.rank = MAX_RANK;
        regInfo.creator = [](const std::string &name) -> std::shared_ptr<DemuxerPlugin> {
            return std::make_shared<Minimp3DemuxerPlugin>(name);
        };
        regInfo.sniffer = Sniff;
        auto rtv = reg->AddPlugin(regInfo);
        if (rtv != Status::OK) {
            MEDIA_LOG_I("RegisterPlugin AddPlugin failed with return %d", static_cast<int>(rtv));
        }
        return Status::OK;
    }
}

PLUGIN_DEFINITION(Minimp3Demuxer, LicenseType::CC0, RegisterPlugin, [] {});
} // namespace Plugin
} // namespace Media
} // namespace OHOS